#include<iostream>
#include<cstdlib>
#include<unistd.h>
#include<cstring>
#include<sys/wait.h>
#include<fcntl.h>
#include<string>

using namespace std;

extern char ** environ;

#define MAX_ARGV 256
#define MAX_ENV 512
int argi = 0;
char* argv[MAX_ARGV];
char* myenv[MAX_ENV];

int PATH_MAX = 256;
int EXIT_CODE = 0;

//重定向相关的
#define NO_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3

int REDIR_STATE = NO_REDIR;
char * filename = nullptr;

int backup [2];
void BackUp()
{
    backup[0] = dup(0);
    backup[1] = dup(1);
}
void Recover()
{
    dup2(backup[0] , 0);
    dup2(backup[1] , 1);
    close(backup[0]);
    close(backup[1]);
}

const char* GetUser()
{
    return getenv("USER") == nullptr ? "null" : getenv("USER");  
}

const char* GetHostName()
{
    static char name[20];
    return gethostname(name,sizeof(name)) == 0 ? name : "null";
}

const char* GetPwd()
{
    return getenv("PWD") == nullptr ? "null" : getenv("PWD");
}

void DispalyPrompt()
{
    printf("%s@%s:%s$ ",GetUser(),GetHostName(),GetPwd());
}

bool GetInput(char buffer[])
{
    fgets(buffer , 256 , stdin);
    buffer[strcspn(buffer,"\n")] = '\0';
    return buffer[0] == '\0' ? false : true;
}

void ParseCommand(char buffer[])
{
    int index = 0;
    argv[index++] = strtok(buffer , " ");
    argi += 1;

    while(argv[index++] = strtok(nullptr , " ")){argi += 1;};
    
    argv[index] = nullptr;
}

void Trim(char*& src)
{
    while(*src == ' ')
    {
        src++;
    }
}

void ParseRedir(char buffer[])
{
    int index = 0;
    while(buffer[index] != '\0')
    {
        if(buffer[index] == '<')
        {
            buffer[index] = '\0';
            filename = &buffer[index]+1;
            Trim(filename);
            REDIR_STATE = INPUT_REDIR;
            break;
        }
        else if (buffer[index] == '>')
        {
            buffer[index] = '\0';
            if(buffer[index+1] == '>')
            {
                cout << "hello i'm > " << endl;
                buffer[index+1] = '\0';
                filename = &buffer[index]+2;
                REDIR_STATE = APPEND_REDIR;
            }
            else
            {
                filename = &buffer[index]+1;
                REDIR_STATE = OUTPUT_REDIR;
            }
            Trim(filename);
            break;
        }
        else 
        {
            index += 1;
        }
    }
}

void InitState();

void ParseInput(char buffer[])
{

    InitState();
    //解析重定向
    ParseRedir(buffer);
    //正常解析命令
    ParseCommand(buffer);

    if(REDIR_STATE != NO_REDIR)
    {
        for(int i = 0 ; argv[i] ; i++)
        {
            if(strcmp(argv[i],"<") == 0 || strcmp(argv[i],">>") == 0 || strcmp(argv[i],">") == 0)
            {
                argv[i] = nullptr;
                break;
            }
        }
    }
}


void Debug()
{
    int index = 0 ;
    for(; argv[index]; index++)
    {
        cout << index << "->" << argv[index] << endl;
    }
    cout << "parameter cnt :" << index << endl;
}

void InitState()
{
    REDIR_STATE = NO_REDIR;
    EXIT_CODE = 0;
    argi = 0;
    filename = nullptr;
}

void DoRedir()
{
    if(REDIR_STATE == INPUT_REDIR)
    {
        int pf = open(filename , O_RDONLY);
        if(pf < 0)
        {
            perror("no such file!!!");
            EXIT_CODE = 1;
            return;
        }
        dup2(pf , 0);
        close(pf);
    }
    else if (REDIR_STATE == OUTPUT_REDIR)
    {
        int pf = open(filename , O_CREAT | O_WRONLY | O_TRUNC , 0666);
        dup2(pf , 1);
        close(pf);
    }
    else if (REDIR_STATE == APPEND_REDIR)
    {
        int pf = open(filename , O_CREAT | O_WRONLY | O_APPEND , 0666);
        dup2(pf , 1);
        close(pf);
    }
    else
    {
        
    }
}

void Execute()
{
    pid_t ret = fork();
    if(ret == 0)
    {
        DoRedir();
        execvp(argv[0] , argv);
        perror("execvp failed");
        EXIT_CODE = 1;
        exit(1);
    }
    else
    {
        int wait_val = -1;
        waitpid(ret , &wait_val , 0);
        EXIT_CODE = WIFEXITED(wait_val) ? WEXITSTATUS(wait_val) : 1; //父进程的退出码
    }
    
}

bool JudgeBuiltIn()
{
    if(strcmp(argv[0] , "cd") == 0)
    {
        const char* path = argi == 1 ? getenv("HOME") : argv[1];
        int ret = chdir(path);
        if(ret == -1)
        {
            perror("chdir filed\n");
            EXIT_CODE = 1;
            return true;
        }

        char buffer[PATH_MAX];
        if(getcwd(buffer , PATH_MAX))
        {
            setenv("PWD" , buffer , 1);
        }
        else
        {
            perror("getcwd fail\n");
            EXIT_CODE = 1;
            exit(1);
            return true;
        }
        EXIT_CODE = 0;
        return true;
        // if(argi == 1)
        // {
        //     const char* home = getenv("HOME");
        //     chdir(home);
        //     setenv("PWD" , getenv("HOME") , 1);
        // }
        // else
        // {
        //     cout << "cd -> " << argv[1] << endl;
        //     chdir(getenv(argv[1]));
        //     setenv("PWD" , getenv("PWD") , 1);
        // }
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
        if(argi < 2)
            return true;
        else if(argv[1][0] == '$')
        {
            BackUp();
            DoRedir();
            if(argv[1][1] == '?')
            {
                
                cout << EXIT_CODE << endl;
            }
            else
            {
                cout << getenv(&argv[1][1]) << endl;
            }
        }
        else
        {
            BackUp();
            DoRedir();
            cout << "echo !!!"  << endl;
            for(int i = 1 ; argv[i] ; i++)
            {
                cout << argv[i] << " ";
            }
            cout << endl;
        }
        EXIT_CODE = 0;
        Recover();
        return true;
    }
    else if(strcmp(argv[0] , "export") == 0)
    {
        int pos = strcspn(argv[1] , "=");
        argv[1][pos] = '\0';
        const char* name = argv[1];
        const char* path = &argv[1][pos+1];
        setenv(name,path,1);
        EXIT_CODE = 0;
        return true;
    }
    return false;
}

void InitEnv()
{
    int i = 0;
    for( ; environ[i]; i++)
    {
        myenv[i] = (char*)malloc(strlen(environ[i]) + 1); //不能用sizeof
        strcpy(myenv[i] , environ[i]);
    }
    myenv[i] = nullptr;

}

void JudgeRedir(char buffer[] , int size)
{
    
}

int main()
{
    InitEnv();
    // for(int i = 0 ; myenv[i] ; i++)
    // {
    //     cout << myenv[i] << endl;
    // }

    while(1)
    {

        DispalyPrompt();
        char buffer[256];
        if(!GetInput(buffer))
            continue;

        ParseInput(buffer);

        if(!(REDIR_STATE == NO_REDIR) && JudgeBuiltIn())
            continue;

        Debug();
        Execute();
    }
    return 0;
}








//#include"new_shell.h"
//Process parameter table

//Enviornmental vairable table
// int main()
// {
//     while(1)
//     {
//         //1,Dispaly Prompt
//         DisplayPrompt();
//         //2,Get Input
//         char input[256];
//         if(!GetInput(input , 256))
//             continue;
//         //3,Parse Input
//         ParseInput(input);
//         //Debug();
//         //4,judgement of built-in instruction
//         if(JudgeBuiltIn())
//         {
//             continue;
//         }
//         //5,execute Input
//         Execute();
//     }
    
//     return 0;
// }











//---------------------------------------------------------------


// #include<cstdio>
// #include<iostream>
// #include<unistd.h>
// #include<sys/wait.h>
// #include"shell.h"
// using namespace std;

// int lastCode = 0;

// extern char ** environ;
// char*  argv[1024] ;
// char*  argc[1024] ;

// int main()
// {

//     while(true)
//     {
//         PromtDisplay();

//         char input[1024];
//         GetInput(input);

//         ParseInput(input);

//         if(IsBuiltIn())
//             continue;
//         //execvp(argv[0],argv);
//         // for(int i = 0 ; argv[i] ; i++)
//         // {
//         //     cout << argv[i] << " ";
//         // }
//         Execute();

//     }
    
//     // int ret = fork();
//     // if(ret == 0)
//     // {
//     //     int num = 5;
//     //     while(num--)
//     //     {
//     //         cout << "子进程在运行" <<endl ;
//     //         sleep(1);
//     //     }
//     //     //exit(100);
//     //     cout << "子进程退出" << endl;
//     // }
//     // else
//     // {
//     //     int pid = 0;
//     //     // wait(&pid);
//     //     // cout << "子进程pid是:" << pid << endl; 
//     //     int num = 7;
//     //     while(num--)
//     //     {
//     //         cout << "父进程在干活" << endl;
//     //         sleep(1);
//     //         waitpid(-1,&pid,WNOHANG);
//     //     }
//     //     cout << "子进程pid:" << pid <<endl;
//     // }

//     return 0;
// }

